package com.kexio.common.util;

import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

import org.springframework.beans.BeanWrapper;
import org.springframework.beans.BeanWrapperImpl;

import com.fasterxml.jackson.databind.ObjectMapper;

/**
 * Bean工具类
 * 
 * @author Kexio Team
 * @since 1.0.0
 */
public class BeanUtils {
    
    private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();
    
    /**
     * 缓存类的字段信息
     */
    private static final Map<Class<?>, Field[]> FIELD_CACHE = new ConcurrentHashMap<>();
    
    private BeanUtils() {
        // 工具类不允许实例化
    }
    
    // ==================== 属性拷贝 ====================
    
    /**
     * 属性拷贝 (Spring BeanUtils的封装)
     */
    public static void copyProperties(Object source, Object target) {
        if (source == null || target == null) {
            return;
        }
        org.springframework.beans.BeanUtils.copyProperties(source, target);
    }
    
    /**
     * 属性拷贝，忽略指定属性
     */
    public static void copyProperties(Object source, Object target, String... ignoreProperties) {
        if (source == null || target == null) {
            return;
        }
        org.springframework.beans.BeanUtils.copyProperties(source, target, ignoreProperties);
    }
    
    /**
     * 属性拷贝，忽略null值
     */
    public static void copyPropertiesIgnoreNull(Object source, Object target) {
        if (source == null || target == null) {
            return;
        }
        
        String[] ignoreProperties = getNullPropertyNames(source);
        org.springframework.beans.BeanUtils.copyProperties(source, target, ignoreProperties);
    }
    
    /**
     * 获取对象中值为null的属性名
     */
    public static String[] getNullPropertyNames(Object source) {
        if (source == null) {
            return new String[0];
        }
        
        BeanWrapper wrapper = new BeanWrapperImpl(source);
        PropertyDescriptor[] pds = wrapper.getPropertyDescriptors();
        
        Set<String> emptyNames = new HashSet<>();
        for (PropertyDescriptor pd : pds) {
            Object srcValue = wrapper.getPropertyValue(pd.getName());
            if (srcValue == null) {
                emptyNames.add(pd.getName());
            }
        }
        
        return emptyNames.toArray(new String[0]);
    }
    
    // ==================== 对象转换 ====================
    
    /**
     * 对象转Map
     */
    public static Map<String, Object> toMap(Object obj) {
        if (obj == null) {
            return new HashMap<>();
        }
        
        if (obj instanceof Map) {
            return (Map<String, Object>) obj;
        }
        
        return OBJECT_MAPPER.convertValue(obj, Map.class);
    }
    
    /**
     * Map转对象
     */
    public static <T> T fromMap(Map<String, Object> map, Class<T> clazz) {
        if (map == null || map.isEmpty()) {
            return null;
        }
        
        return OBJECT_MAPPER.convertValue(map, clazz);
    }
    
    /**
     * 对象转换 (通过JSON序列化实现深拷贝)
     */
    public static <T> T convert(Object source, Class<T> targetClass) {
        if (source == null) {
            return null;
        }
        
        return OBJECT_MAPPER.convertValue(source, targetClass);
    }
    
    /**
     * 列表转换
     */
    public static <S, T> List<T> convertList(List<S> sourceList, Class<T> targetClass) {
        if (sourceList == null || sourceList.isEmpty()) {
            return new ArrayList<>();
        }
        
        List<T> targetList = new ArrayList<>(sourceList.size());
        for (S source : sourceList) {
            T target = convert(source, targetClass);
            if (target != null) {
                targetList.add(target);
            }
        }
        return targetList;
    }
    
    // ==================== 反射操作 ====================
    
    /**
     * 获取对象的所有字段 (包括父类)
     */
    public static Field[] getAllFields(Class<?> clazz) {
        if (clazz == null) {
            return new Field[0];
        }
        
        return FIELD_CACHE.computeIfAbsent(clazz, key -> {
            List<Field> fields = new ArrayList<>();
            Class<?> currentClass = key;
            
            while (currentClass != null && currentClass != Object.class) {
                Field[] declaredFields = currentClass.getDeclaredFields();
                Collections.addAll(fields, declaredFields);
                currentClass = currentClass.getSuperclass();
            }
            
            return fields.toArray(new Field[0]);
        });
    }
    
    /**
     * 获取字段值
     */
    public static Object getFieldValue(Object obj, String fieldName) {
        if (obj == null || StringUtils.isEmpty(fieldName)) {
            return null;
        }
        
        try {
            Field field = findField(obj.getClass(), fieldName);
            if (field == null) {
                return null;
            }
            
            field.setAccessible(true);
            return field.get(obj);
        } catch (Exception e) {
            throw new RuntimeException("获取字段值失败: " + fieldName, e);
        }
    }
    
    /**
     * 设置字段值
     */
    public static void setFieldValue(Object obj, String fieldName, Object value) {
        if (obj == null || StringUtils.isEmpty(fieldName)) {
            return;
        }
        
        try {
            Field field = findField(obj.getClass(), fieldName);
            if (field == null) {
                throw new NoSuchFieldException("字段不存在: " + fieldName);
            }
            
            field.setAccessible(true);
            field.set(obj, value);
        } catch (Exception e) {
            throw new RuntimeException("设置字段值失败: " + fieldName, e);
        }
    }
    
    /**
     * 查找字段 (包括父类)
     */
    public static Field findField(Class<?> clazz, String fieldName) {
        if (clazz == null || StringUtils.isEmpty(fieldName)) {
            return null;
        }
        
        Class<?> currentClass = clazz;
        while (currentClass != null && currentClass != Object.class) {
            try {
                return currentClass.getDeclaredField(fieldName);
            } catch (NoSuchFieldException e) {
                currentClass = currentClass.getSuperclass();
            }
        }
        return null;
    }
    
    /**
     * 调用方法
     */
    public static Object invokeMethod(Object obj, String methodName, Object... args) {
        if (obj == null || StringUtils.isEmpty(methodName)) {
            return null;
        }
        
        try {
            Class<?>[] paramTypes = new Class[args.length];
            for (int i = 0; i < args.length; i++) {
                paramTypes[i] = args[i] != null ? args[i].getClass() : Object.class;
            }
            
            Method method = findMethod(obj.getClass(), methodName, paramTypes);
            if (method == null) {
                throw new NoSuchMethodException("方法不存在: " + methodName);
            }
            
            method.setAccessible(true);
            return method.invoke(obj, args);
        } catch (Exception e) {
            throw new RuntimeException("调用方法失败: " + methodName, e);
        }
    }
    
    /**
     * 查找方法 (包括父类)
     */
    public static Method findMethod(Class<?> clazz, String methodName, Class<?>... paramTypes) {
        if (clazz == null || StringUtils.isEmpty(methodName)) {
            return null;
        }
        
        Class<?> currentClass = clazz;
        while (currentClass != null && currentClass != Object.class) {
            try {
                return currentClass.getDeclaredMethod(methodName, paramTypes);
            } catch (NoSuchMethodException e) {
                // 尝试匹配参数类型兼容的方法
                Method[] methods = currentClass.getDeclaredMethods();
                for (Method method : methods) {
                    if (method.getName().equals(methodName) && 
                        isParameterTypesMatch(method.getParameterTypes(), paramTypes)) {
                        return method;
                    }
                }
                currentClass = currentClass.getSuperclass();
            }
        }
        return null;
    }
    
    /**
     * 判断参数类型是否匹配
     */
    private static boolean isParameterTypesMatch(Class<?>[] methodParamTypes, Class<?>[] argTypes) {
        if (methodParamTypes.length != argTypes.length) {
            return false;
        }
        
        for (int i = 0; i < methodParamTypes.length; i++) {
            if (!methodParamTypes[i].isAssignableFrom(argTypes[i])) {
                return false;
            }
        }
        return true;
    }
    
    // ==================== 对象比较 ====================
    
    /**
     * 比较两个对象的属性差异
     */
    public static Map<String, Object[]> compareObjects(Object obj1, Object obj2) {
        if (obj1 == null && obj2 == null) {
            return new HashMap<>();
        }
        
        if (obj1 == null || obj2 == null) {
            Map<String, Object[]> diff = new HashMap<>();
            diff.put("object", new Object[]{obj1, obj2});
            return diff;
        }
        
        if (!obj1.getClass().equals(obj2.getClass())) {
            throw new IllegalArgumentException("对象类型不匹配");
        }
        
        Map<String, Object[]> differences = new HashMap<>();
        Field[] fields = getAllFields(obj1.getClass());
        
        for (Field field : fields) {
            try {
                field.setAccessible(true);
                Object value1 = field.get(obj1);
                Object value2 = field.get(obj2);
                
                if (!Objects.equals(value1, value2)) {
                    differences.put(field.getName(), new Object[]{value1, value2});
                }
            } catch (Exception e) {
                // 忽略无法访问的字段
            }
        }
        
        return differences;
    }
    
    // ==================== 实例创建 ====================
    
    /**
     * 创建类的实例
     */
    public static <T> T newInstance(Class<T> clazz) {
        if (clazz == null) {
            return null;
        }
        
        try {
            return clazz.getDeclaredConstructor().newInstance();
        } catch (Exception e) {
            throw new RuntimeException("创建实例失败: " + clazz.getName(), e);
        }
    }
    
    /**
     * 判断类是否存在
     */
    public static boolean isClassPresent(String className) {
        try {
            Class.forName(className);
            return true;
        } catch (ClassNotFoundException e) {
            return false;
        }
    }
    
    // ==================== 属性操作 ====================
    
    /**
     * 获取对象的所有属性名
     */
    public static Set<String> getPropertyNames(Object obj) {
        if (obj == null) {
            return new HashSet<>();
        }
        
        Set<String> propertyNames = new HashSet<>();
        BeanWrapper wrapper = new BeanWrapperImpl(obj);
        PropertyDescriptor[] pds = wrapper.getPropertyDescriptors();
        
        for (PropertyDescriptor pd : pds) {
            if (pd.getReadMethod() != null && !"class".equals(pd.getName())) {
                propertyNames.add(pd.getName());
            }
        }
        
        return propertyNames;
    }
    
    /**
     * 获取对象的所有属性值
     */
    public static Map<String, Object> getPropertyValues(Object obj) {
        if (obj == null) {
            return new HashMap<>();
        }
        
        Map<String, Object> propertyValues = new HashMap<>();
        BeanWrapper wrapper = new BeanWrapperImpl(obj);
        PropertyDescriptor[] pds = wrapper.getPropertyDescriptors();
        
        for (PropertyDescriptor pd : pds) {
            if (pd.getReadMethod() != null && !"class".equals(pd.getName())) {
                try {
                    Object value = wrapper.getPropertyValue(pd.getName());
                    propertyValues.put(pd.getName(), value);
                } catch (Exception e) {
                    // 忽略无法读取的属性
                }
            }
        }
        
        return propertyValues;
    }
    
    /**
     * 批量设置属性值
     */
    public static void setPropertyValues(Object obj, Map<String, Object> propertyValues) {
        if (obj == null || propertyValues == null || propertyValues.isEmpty()) {
            return;
        }
        
        BeanWrapper wrapper = new BeanWrapperImpl(obj);
        for (Map.Entry<String, Object> entry : propertyValues.entrySet()) {
            try {
                if (wrapper.isWritableProperty(entry.getKey())) {
                    wrapper.setPropertyValue(entry.getKey(), entry.getValue());
                }
            } catch (Exception e) {
                // 忽略无法设置的属性
            }
        }
    }
}
